import gitlab
import os
import shutil
import subprocess
import json
import logging
import time
import requests






# 配置日志记录
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')

 
# 在此处替换为原服务器和新服务器的GitLab URL和访问令牌
source_url = 'https://demo.lichengjun.top:65530'
source_token = 'jdTh7P1QU7CmbZNgsBaT'  # 请替换为您的源GitLab访问令牌


target_url = 'https://gitlab.lichengjun.top'  # 'https://gitlab.lichengjun.top:63922'
target_k8s_url = 'http://gitlab.lichengjun.top'  # 这个地址是因为我在 k8s 中部署 gitlab 时，没有选择默认的ingress,而是选择 kubesphere 中的集群网关造成的，如果部署的gitlab没有这个问题，可以不用管
target_token = 'glpat-1DKM_RUDsi_zd4o4z6c5'  # 请替换为您的目标GitLab访问令牌


clone_project_deposit_path = '/root/python/gitlab/project'  # 从源gitlab 克隆代码的存放路径
users_error_log_file_path = os.path.join(clone_project_deposit_path, 'users-error.txt')  # 存放处理用户错误日志
groups_error_log_file_path = os.path.join(clone_project_deposit_path, 'groups-error.txt')  # 存放处理群组错误日志
groups_members_error_log_file_path = os.path.join(clone_project_deposit_path, 'groups-members-error.txt')  # 存放处理群组成员错误日志
projects_error_log_file_path = os.path.join(clone_project_deposit_path, 'projects-error.txt')  # 存放处理项目错误日志
projects_members_error_log_file_path = os.path.join(clone_project_deposit_path, 'projects-members-error.txt')  # 存放处理项目错误日志


# 连接到GitLab实例
source_gitlab = gitlab.Gitlab(source_url, private_token=source_token)
target_gitlab = gitlab.Gitlab(target_url, private_token=target_token)


users_password = "Yztx@2023"  # 在此处替换为新用户的密码,为了方便，我们这边设置成统一的密码，后面让用户自己在去重置



# 指定克隆项目的存储路径，清理脏数据
def init():
    print(f" 。。。。。。…………………………………………………………………………………………………………………………………………………………………………………………………………  指定克隆项目的存储路径，清理脏数据 开始 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ")
    logging.info(f"为防止有脏数据，删除该存储路径")
    if os.path.exists(clone_project_deposit_path):
        try:
            shutil.rmtree(clone_project_deposit_path)
            print(f"目录 '{clone_project_deposit_path}' 已成功删除")
        except Exception as e:
            print(f"删除目录 '{clone_project_deposit_path}' 时出错: {e}")
    print(f"                                                                                             ")        
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 指定克隆项目的存储路径，清理脏数据 结束 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")
    print(f"                                                                                             ")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")


    




# 删除目标gitlab上的所有项目
def delete_target_all_projects():
    print(f" 。。。。。。…………………………………………………………………………………………………………………………………………………………………………………………………………  将目标gitlab上的项目全部删除 开始 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ")   
    try:        
        i = 0
        logging.info(f"分页获取所有项目，避免一次性加载过多数据，假设最多200页，根据实际情况调整")        
        for page in range(1, 200):
            print(f" 。。。。。。................................................................................................................................................................................................ 。。。。。。")          
            target_projects = target_gitlab.projects.list(per_page=100, page=page)
            if not target_projects:
                logging.info(f"已经获取完所有项目，退出循环")
                break
            for target_project in target_projects:
                print(f" 。。。。。。。…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........………………………….......... 。。。。。。")
                i += 1
                print(f"")
                print(f"")
                print(f"当前处理第 {i} 个项目")
                print(f"") 
                print(f"")              
                try:
                    target_project.delete()
                    logging.info(f"删除项目> {target_project.name} : {target_project.path_with_namespace} 成功")
                    time.sleep(5)
                except gitlab.exceptions.GitlabDeleteError as e:
                    logging.error(f"删除项目> {target_project.name} : {target_project.path_with_namespace} 失败: {e}")                
    except gitlab.exceptions.GitlabGetError as e:
        logging.error(f"获取项目列表失败: {e}")
    print(f"                                                                                             ")        
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将目标gitlab上的项目全部删除 结束 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")
    print(f"                                                                                             ")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")






# 删除目标gitlab上的所有用户
def delete_target_all_users():
    print(f" 。。。。。。…………………………………………………………………………………………………………………………………………………………………………………………………………  将目标gitlab上的用户全部删除 开始 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ")
    try:
        i = 0
        logging.info(f"分页获取所有用户，避免一次性加载过多数据，假设最多200页，根据实际情况调整")        
        for page in range(1, 200):
            print(f" 。。。。。。................................................................................................................................................................................................ 。。。。。。")          
            logging.info(f"获取每页100个用户")
            target_users = target_gitlab.users.list(per_page=100, page=page) 
            if not target_users:
                logging.info(f"已经获取完所有用户，退出循环")
                break    
            for target_user in target_users:
                print(f" 。。。。。。。…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........………………………….......... 。。。。。。")
                if (target_user.username == 'root'):
                    logging.info(f"排除 root 用户")
                    continue
                i += 1
                print(f"")
                print(f"")
                print(f"当前处理第 {i} 个用户")
                print(f"") 
                print(f"")    
                try:
                    target_user.delete()
                    logging.info(f"删除用户> {target_user.name} : {target_user.username} 成功")
                    time.sleep(5)
                except (exceptions.GitlabGetError, exceptions.GitlabDeleteError, requests.exceptions.ConnectionError) as e:
                    logging.error(f"删除用户> {target_user.name} : {target_user.username} 失败: {e}")
            time.sleep(60)        
    except gitlab.exceptions.GitlabGetError as e:
        logging.error(f"获取用户列表失败: {e}")
    print(f"                                                                                             ")        
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将目标gitlab上的用户全部删除 结束 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")
    print(f"                                                                                             ")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")






# 删除目标gitlab上的所有群组
def delete_target_all_groups(): 
    print(f" 。。。。。。…………………………………………………………………………………………………………………………………………………………………………………………………………  将目标gitlab上的群组全部删除 开始 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ")   
    try:        
        i = 0
        logging.info(f"分页获取所有群组，避免一次性加载过多数据，假设最多200页，根据实际情况调整")        
        for page in range(1, 200):
            print(f" 。。。。。。................................................................................................................................................................................................ 。。。。。。")            
            logging.info(f"获取每页100个群组")
            target_groups = target_gitlab.groups.list(per_page=100, page=page, order_by='id', sort='desc')
            if not target_groups:
                logging.info(f"已经获取完所有群组，退出循环")
                break
            for target_group in target_groups:
                print(f" 。。。。。。。…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........………………………….......... 。。。。。。")
                i += 1
                print(f"")
                print(f"")
                print(f"当前处理第 {i} 个群组")
                print(f"") 
                print(f"")    
                try:
                    target_group.delete()
                    logging.info(f"删除群组> {target_group.name} : {target_group.full_path} 成功")
                    time.sleep(5)
                except gitlab.exceptions.GitlabDeleteError as e:
                    logging.error(f"删除群组> {target_group.name} : {target_group.full_path} 失败: {e}")
    except gitlab.exceptions.GitlabGetError as e:
        logging.error(f"获取群组列表失败: {e}")
    print(f"                                                                                             ")        
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将目标gitlab上的群组全部删除 结束 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")
    print(f"                                                                                             ")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")







# 将源gitlab上的单个用户同步到目标gitlab上
def sync_target_single_user_by_source_single_user(source_user_id):
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的单个用户同步到目标gitlab上 开始 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ")
    try:        
        logging.info(f"获取要同步的用户信息")
        # 通过id 获取用户
        source_user = source_gitlab.users.get(source_user_id)        
        if (source_user.username != 'root'):
            logging.info(f"排除 root 用户")             
            logging.info(f"在目标gitlab中搜索 {source_user.username} 用户")
            users = target_gitlab.users.list(username=source_user.username)
            if not len(users):
                logging.info(f"在目标gitlab中不存在 {source_user.name} : {source_user.username} 用户，配置用户信息") 
                user_data = {
                    'email': source_user.email,
                    'password': users_password,
                    'username': source_user.username,
                    'name': source_user.name
                }
                try:
                    logging.info(f"在目标gitlab中创建 {source_user.name} : {source_user.username}  用户")
                    user = target_gitlab.users.create(user_data)                        
                    if source_user.state == 'blocked':
                        logging.info(f"在目标gitlab中封禁 {source_user.name} : {source_user.username}  用户")
                        user.ban()  
                except gitlab.exceptions.GitlabCreateError as e:
                    logging.error(f"在目标gitlab中创建 {source_user.name} : {source_user.username}  用户时发生意外错误: {e}")
                    with open(users_error_log_file_path, 'a') as file:
                        file.write(f"sync_target_users_by_source_users: 创建用户> {source_user.name} : {source_user.username}  source_user_id: {source_user_id} 时出错.\n")
            else:
                logging.info(f"在目标gitlab中已经存在 {source_user.username} 用户")               
    except gitlab.exceptions.GitlabGetError as e:
        logging.error(f"获取用户失败: {e}")                            
    print(f"                                                                                             ")        
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的单个用户同步到目标gitlab上 结束 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")
    print(f"                                                                                             ")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")





# 将源gitlab上的用户同步到目标gitlab上
def sync_target_users_by_source_users():
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的用户同步到目标gitlab上 开始 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ")
    try:
        i = 0
        logging.info(f"分页获取所有用户，避免一次性加载过多数据，假设最多200页，根据实际情况调整")
        for page in range(1, 200):
            print(f" 。。。。。。................................................................................................................................................................................................ 。。。。。。")           
            logging.info(f"获取每页100个用户")            
            source_users = source_gitlab.users.list(per_page=100, page=page, order_by='id', sort='asc')
            if not source_users:
                logging.info(f"已经获取完所有用户，退出循环")
                break
            for source_user in source_users:
                print(f" 。。。。。。。…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........………………………….......... 。。。。。。")
                i += 1
                print(f"")
                print(f"")
                print(f"当前处理第 {i} 个用户")
                print(f"") 
                print(f"")     


                # 这里的判断用于当意外导致同步中断，我们可以通过这个断点继续后面的操作，不用再重复执行已经同步好的操作
                if i < 0:
                    continue 


                if (source_user.username == 'root'):
                    logging.info(f"排除 root 用户")
                    continue
                logging.info(f"在目标gitlab中搜索 {source_user.username} 用户")
                users = target_gitlab.users.list(username=source_user.username)
                if not len(users):
                    logging.info(f"在目标gitlab中不存在 {source_user.name} : {source_user.username} 用户，配置用户信息") 
                    user_data = {
                        'email': source_user.email,
                        'password': users_password,
                        'username': source_user.username,
                        'name': source_user.name
                    }
                    try:
                        logging.info(f"在目标gitlab中创建 {source_user.name} : {source_user.username}  用户")
                        user = target_gitlab.users.create(user_data)                        
                        time.sleep(5) 
                        if source_user.state == 'blocked':
                            logging.info(f"在目标gitlab中封禁 {source_user.name} : {source_user.username}  用户")
                            user.ban()  
                    except gitlab.exceptions.GitlabCreateError as e:
                        logging.error(f"在目标gitlab中创建 {source_user.name} : {source_user.username}  用户时发生意外错误: {e}")
                        with open(users_error_log_file_path, 'a') as file:
                            file.write(f"sync_target_users_by_source_users: 创建用户> {source_user.name} : {source_user.username}  source_user_id: {source_user.id} 时出错.\n")
                else:
                    logging.info(f"在目标gitlab中已经存在 {source_user.username} 用户") 
            time.sleep(60)           
    except gitlab.exceptions.GitlabGetError as e:
        logging.error(f"获取用户列表失败: {e}")                            
    print(f"                                                                                             ")        
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的用户同步到目标gitlab上 结束 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")
    print(f"                                                                                             ")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")







# 将源gitlab上的单个群组同步到目标gitlab上
def sync_target_single_groups_by_single_source_groups(source_group_id):
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的单个群组同步到目标gitlab上 开始 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ")
    try:        
        logging.info(f"获取要同步的群组信息")
        source_group = source_gitlab.groups.get(source_group_id)       
        logging.info(f"在目标gitlab中搜索 {source_group.full_path} 群组")
        target_groups = target_gitlab.groups.list(search=source_group.full_path, get_all=True)   
        found = False  # 初始化群组是否存在标志变量             
        for target_group in target_groups:
            if target_group.full_path == source_group.full_path:
                found = True
                logging.info(f"目标gitlab存在：{source_group.full_path} 群组")
                break                
        if not found:
            logging.info(f"目标gitlab不存在：{source_group.full_path} 群组")
            parent_id = None
            if source_group.parent_id:
                logging.info(f"源gitlab {source_group.full_path} 群组为子组，需要查找其父组")
                source_parent_group = source_gitlab.groups.get(source_group.parent_id)
                logging.info(f"源gitlab {source_group.full_path} 子群组其父组为 {source_parent_group.full_path}")
                logging.info(f"在目标gitlab中查找其父组")
                target_parent_groups = target_gitlab.groups.list(search=source_parent_group.full_path, get_all=True)                        
                for target_parent_group in target_parent_groups:
                    if target_parent_group.full_path == source_parent_group.full_path:
                        parent_id = target_parent_group.id
                        break    
            logging.info(f"配置群组信息")
            group_data = {
                'name': source_group.name, 
                'path': source_group.path, 
                'description': source_group.description, 
                'visibility': source_group.visibility, 
                'request_access_enabled': source_group.request_access_enabled,
                'parent_id': parent_id
            }
            try:
                logging.info(f"在目标gitlab中创建 {source_group.name} : {source_group.full_path} 群组")               
                target_gitlab.groups.create(group_data)
            except gitlab.exceptions.GitlabCreateError as e:
                logging.error(f"创建 {source_group.name} : {source_group.full_path} 群组时发生意外错误: {e}")
                with open(groups_error_log_file_path, 'a') as file:
                    file.write(f"sync_target_groups_by_source_groups: 创建群组> {source_group.name} : {source_group.full_path}  source_group_id: {source_group_id} 时出错.\n")     
    except gitlab.exceptions.GitlabGetError as e:
        logging.error(f"获取群组失败: {e}")                            
    print(f"                                                                                             ")        
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的单个群组同步到目标gitlab上 结束 …………………………………………………………………………………………………………………………………………………………………………………………………………。。。。。。")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")
    print(f"                                                                                             ")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")
    
    
    
    
    
# 将源gitlab上的群组同步到目标gitlab上
def sync_target_groups_by_source_groups():
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的群组同步到目标gitlab上 开始 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ")
    try:
        i = 0
        logging.info(f"分页获取所有群组，避免一次性加载过多数据，假设最多200页，根据实际情况调整")
        for page in range(1, 200):
            print(f" 。。。。。。................................................................................................................................................................................................ 。。。。。。")           
            logging.info(f"获取每页100个群组")
            logging.info(f"获取源gitlab上的所有群组, 并且按照 id 进行顺序排序，防止遍历出现子群组在父组前面")
            source_groups = source_gitlab.groups.list(per_page=100, page=page, order_by='id', sort='asc')
            if not source_groups:
                logging.info(f"已经获取完所有群组，退出循环")
                break
            for source_group in source_groups:
                print(f" 。。。。。。。…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........………………………….......... 。。。。。。")
                i += 1
                print(f"")
                print(f"")
                print(f"当前处理第 {i} 个群组")
                print(f"") 
                print(f"")            
                found = False  # 初始化群组是否存在标志变量


                # 这里的判断用于当意外导致同步中断，我们可以通过这个断点继续后面的操作，不用再重复执行已经同步好的操作
                if i < 0:
                    continue 


                logging.info(f"在目标gitlab中搜索 {source_group.full_path} 群组")
                target_groups = target_gitlab.groups.list(search=source_group.full_path, get_all=True)                
                for target_group in target_groups:
                    if target_group.full_path == source_group.full_path:
                        found = True
                        logging.info(f"目标gitlab存在：{source_group.full_path} 群组")
                        break                
                if not found:
                    logging.info(f"目标gitlab不存在：{source_group.full_path} 群组")
                    parent_id = None
                    if source_group.parent_id:
                        logging.info(f"源gitlab {source_group.full_path} 群组为子组，需要查找其父组")
                        source_parent_group = source_gitlab.groups.get(source_group.parent_id)
                        logging.info(f"源gitlab {source_group.full_path} 子群组其父组为 {source_parent_group.full_path}")
                        logging.info(f"在目标gitlab中查找其父组")
                        target_parent_groups = target_gitlab.groups.list(search=source_parent_group.full_path, get_all=True)                        
                        for target_parent_group in target_parent_groups:
                            if target_parent_group.full_path == source_parent_group.full_path:
                                parent_id = target_parent_group.id
                                break    
                    logging.info(f"配置群组信息")
                    group_data = {
                        'name': source_group.name, 
                        'path': source_group.path, 
                        'description': source_group.description, 
                        'visibility': source_group.visibility, 
                        'request_access_enabled': source_group.request_access_enabled,
                        'parent_id': parent_id
                    }
                    try:                       
                        time.sleep(5)
                        logging.info(f"在目标gitlab中创建 {source_group.name} : {source_group.full_path} 群组")               
                        target_gitlab.groups.create(group_data)
                    except gitlab.exceptions.GitlabCreateError as e:
                        logging.error(f"创建 {source_group.name} : {source_group.full_path} 群组时发生意外错误: {e}")
                        with open(groups_error_log_file_path, 'a') as file:
                            file.write(f"sync_target_groups_by_source_groups: 创建群组> {source_group.name} : {source_group.full_path}  source_group_id: {source_group.id} 时出错.\n")     
    except gitlab.exceptions.GitlabGetError as e:
        logging.error(f"获取群组列表失败: {e}")                            
    print(f"                                                                                             ")        
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的群组同步到目标gitlab上 结束 …………………………………………………………………………………………………………………………………………………………………………………………………………。。。。。。")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")
    print(f"                                                                                             ")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")







# 将源gitlab上的群组的单个组成员同步到目标gitlab上
def sync_target_group_single_members_by_source_group_single_members(target_group_id, target_user_id, access_level):
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的群组的单个组成员同步到目标gitlab上 开始 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ")
    try:
        logging.info(f"获取要同步的群组信息")
        target_group = target_gitlab.groups.get(target_group_id)
        logging.info(f"获取要同步的用户信息")
        target_user = target_gitlab.users.get(target_user_id)
        logging.info(f"获取要同步的群组成员信息") 
        target_group.members_all.get(target_user_id)
        logging.info(f"在目标gitlab中，群组 {target_group.full_path} 已经存在组成员 {target_user.username}")  
        try:
            logging.info(f"在目标gitlab中，群组 {target_group.full_path} 不存在组成员 {target_user.username}，将其添加到群组中")
            target_group.members.create({'user_id': target_user_id, 'access_level': access_level})
        except gitlab.exceptions.GitlabCreateError as e:
            logging.error(f"在目标 GitLab 群组中添加组成员时出错: {e}")
            with open(groups_members_error_log_file_path, 'a') as file:
                file.write(f"sync_target_group_single_members_by_source_group_single_members: 群组中添加组成员> {target_group.full_path} : {target_user.username}  target_user_id: {target_user_id}  access_level: {access_level} 时出错.\n")
    except gitlab.exceptions.GitlabGetError as e:
        logging.error(f"获取群组-用户-群组成员信息失败: {e}") 
    print(f"                                                                                             ")                
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的群组的单个组成员同步到目标gitlab上 结束 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")
    print(f"                                                                                             ")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")






# 将源gitlab上的群组的组成员同步到目标gitlab上
def sync_target_group_members_by_source_group_members():
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的群组的组成员同步到目标gitlab上 开始 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ")
    try:
        i = 0
        logging.info(f"分页获取所有群组，避免一次性加载过多数据，假设最多200页，根据实际情况调整")
        for page in range(1, 200):
            print(f" 。。。。。。................................................................................................................................................................................................ 。。。。。。") 
            logging.info(f"获取每页100个群组, 并且按照 id 进行顺序排序，防止遍历出现子群组在父组前面")
            source_groups = source_gitlab.groups.list(per_page=100, page=page, order_by='id', sort='asc')
            if not source_groups:
                logging.info(f"已经获取完所有群组，退出循环")
                break
            for source_group in source_groups:
                print(f" 。。。。。。。…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........………………………….......... 。。。。。。")
                i += 1
                print(f"")
                print(f"")
                print(f"当前处理第 {i} 个群组")
                print(f"") 
                print(f"")     

              
                # 这里的判断用于当意外导致同步中断，我们可以通过这个断点继续后面的操作，不用再重复执行已经同步好的操作
                if i < 0:
                    continue 


                logging.info(f"递归 {source_group.full_path} 群组组成员（包括通过祖先组继承的成员")
                source_group_members = source_group.members_all.list(get_all=True)
                logging.info(f"在目标gitlab中查找 {source_group.full_path} 群组")
                target_groups = target_gitlab.groups.list(search=source_group.full_path, get_all=True)
                for target_group in target_groups:
                    if target_group.full_path == source_group.full_path:
                        for source_group_member in source_group_members:
                            print(f" 。。。。。。。…………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………….. 。。。。。。")
                            logging.info(f"在目标gitlab中查找群组 {target_group.full_path} 组成员 {source_group_member.username} 用户id")                            
                            user_id = target_gitlab.users.list(username=source_group_member.username)[0].id                            
                            try:
                                target_group.members_all.get(user_id)
                                logging.info(f"在目标gitlab中，群组 {target_group.full_path} 已经存在组成员 {source_group_member.username}")
                            except gitlab.exceptions.GitlabGetError:
                                try:
                                    logging.info(f"在目标gitlab中，群组 {target_group.full_path} 不存在组成员 {source_group_member.username}，将其添加到群组中")
                                    target_group.members.create({'user_id': user_id, 'access_level': source_group_member.access_level})
                                    time.sleep(5)
                                except gitlab.exceptions.GitlabCreateError as e:
                                    logging.error(f"在目标 GitLab 群组中添加组成员时出错: {e}")
                                    with open(groups_members_error_log_file_path, 'a') as file:
                                        file.write(f"sync_target_groups_by_source_groups: 群组中添加组成员> {target_group.full_path} : {source_group_member.username}  target_group_id: {target_group.id}  target_user_id: {user_id}  access_level: {source_group_member.access_level} 时出错.\n")     
                        break
    except gitlab.exceptions.GitlabGetError as e:
        logging.error(f"获取群组的组成员列表失败: {e}")                        
    print(f"                                                                                             ")                
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的群组的组成员同步到目标gitlab上 结束 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")
    print(f"                                                                                             ")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")







# 将源gitlab上的单个项目同步到目标gitlab上
def sync_target_single_projects_by_source_single_projects(source_project_id):
    print(f" 。。。。。。…………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的单个项目同步到目标gitlab上 开始 …………………………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ")
    try:
        logging.info(f"获取要同步的项目信息")
        source_project = source_gitlab.projects.get(source_project_id)
        logging.info(f"处理项目> {source_project.name} : {source_project.path_with_namespace} ")
        kind = source_project.namespace['kind']
        logging.info(f"项目类型: {kind} ")
        source_user_or_group = source_project.namespace['full_path']
        logging.info(f"当前项目> {source_project.name} : {source_project.path_with_namespace} 的所属用户或者群组：{source_user_or_group}")
        try:
            logging.info(f"按名称和命名空间查找项目")
            target_project = target_gitlab.projects.get(source_project.path_with_namespace)
            logging.info(f"项目 {source_project.path_with_namespace} 在目标 GitLab 中已存在，跳过创建")
            logging.info(f"克隆并推送项目> {source_project.name} : {source_project.path_with_namespace}")
            clone_and_push_project(source_project, target_project)
        except gitlab.exceptions.GitlabGetError as e:
            logging.info(f"项目> {source_project.name} : {source_project.path_with_namespace} 在目标 GitLab 中不存在，需要创建")
            logging.info(f"检查目标 GitLab 中是否已存在同名项目（分为用户和群组两类）")
            if kind == "user":
                try:
                    logging.info(f"项目> {source_project.name} : {source_project.path_with_namespace} 属于 用户")                            
                    target_user = target_gitlab.users.list(username=source_user_or_group)[0]
                    logging.info(f"项目的所属用户：{target_user.username}")                           
                    logging.info(f"为用户 {target_user.username} 创建项目，仅限管理员才有权操作")
                    target_project = target_user.projects.create({'name': source_project.name})
                    logging.info(f"克隆并推送项目> {source_project.name} : {source_project.path_with_namespace}")
                    clone_and_push_project(source_project, target_project)
                except gitlab.exceptions.GitlabCreateError as e:
                    logging.error(f"在目标 GitLab 中创建项目> {source_project.name} : {source_project.path_with_namespace} 时出错: {e}")
                    with open(projects_error_log_file_path, 'a') as file:
                        file.write(f"sync_target_projects_by_source_projects: 创建项目> {source_project.name} : {source_project.path_with_namespace}  source_project_id: {source_project.id} 时出错.\n")     
            else:
                try:
                    logging.info(f"项目> {source_project.name} : {source_project.path_with_namespace} 属于 群组")                            
                    target_groups = target_gitlab.groups.list(search=source_user_or_group, get_all=True)
                    target_group_id = None
                    found = False   # 初始化项目是否存在标志变量  
                    for target_group in target_groups:
                        if target_group.full_path == source_user_or_group:
                            found = True
                            target_group_id = target_group.id
                            break
                    if  found:                                                                                          
                        logging.info(f"配置项目信息") 
                        project_data = {
                            'name': source_project.name, 
                            'path': source_project.path, 
                            'description': source_project.description, 
                            'visibility': source_project.visibility,                                 
                            'namespace_id': target_group_id
                        }       
                        logging.info(f"在 {source_user_or_group} : {target_group.id} 群组中创建项目> {source_project.name} : {source_project.path_with_namespace}")                        
                        target_project = target_gitlab.projects.create(project_data)
                        logging.info(f"sync_target_projects_by_source_projects: 克隆并推送项目> {source_project.name} : {source_project.path_with_namespace}")
                        clone_and_push_project(source_project, target_project)
                except gitlab.exceptions.GitlabCreateError as e:
                    logging.error(f"在目标 GitLab 中创建项目> {source_project.name} : {source_project.path_with_namespace} 时出错: {e}")
                    with open(projects_error_log_file_path, 'a') as file:
                        file.write(f"sync_target_projects_by_source_projects: 创建项目> {source_project.name} : {source_project.path_with_namespace}  source_project_id: {source_project.id} 时出错.\n")                         
    except gitlab.exceptions.GitlabGetError as e:
        logging.error(f"获取项目失败: {e}")
    print(f"                                                                                             ")    
    print(f" 。。。。。。…………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的单个项目同步到目标gitlab上 结束 …………………………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")
    print(f"                                                                                             ")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")





    
# 将源gitlab上的项目同步到目标gitlab上
def sync_target_projects_by_source_projects():
    print(f" 。。。。。。…………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的项目同步到目标gitlab上 开始 …………………………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ")
    try:
        i = 0
        logging.info(f"分页获取所有项目，避免一次性加载过多数据，假设最多200页，根据实际情况调整")
        for page in range(1, 200):      
            logging.info(f"获取每页100个项目")
            source_projects = source_gitlab.projects.list(per_page=100, page=page, order_by='id', sort='asc')
            if not source_projects:
                logging.info(f"已经获取完所有项目，退出循环")
                break
            for source_project in source_projects:
                print(f" 。。。。。。................................................................................................................................................................................................ 。。。。。。") 
                i += 1
                print(f"")
                print(f"")
                print(f"当前处理第 {i} 个项目")
                print(f"") 
                print(f"")    
                found = False  # 初始化项目是否存在标志变量  

                
                # 这里的判断用于当意外导致同步中断，我们可以通过这个断点继续后面的操作，不用再重复执行已经同步好的操作
                if i < 0:
                    continue 

 

                logging.info(f"处理项目> {source_project.name} : {source_project.path_with_namespace} ")
                kind = source_project.namespace['kind']
                logging.info(f"项目类型: {kind} ")
                source_user_or_group = source_project.namespace['full_path']
                logging.info(f"当前项目> {source_project.name} : {source_project.path_with_namespace} 的所属用户或者群组：{source_user_or_group}")
                try:
                    logging.info(f"按名称和命名空间查找项目")
                    target_project = target_gitlab.projects.get(source_project.path_with_namespace)
                    logging.info(f"项目 {source_project.path_with_namespace} 在目标 GitLab 中已存在，跳过创建")
                    logging.info(f"克隆并推送项目> {source_project.name} : {source_project.path_with_namespace}")
                    clone_and_push_project(source_project, target_project)
                except gitlab.exceptions.GitlabGetError as e:
                    logging.info(f"项目> {source_project.name} : {source_project.path_with_namespace} 在目标 GitLab 中不存在，需要创建")
                    logging.info(f"检查目标 GitLab 中是否已存在同名项目（分为用户和群组两类）")
                    if kind == "user":
                        try:
                            logging.info(f"项目> {source_project.name} : {source_project.path_with_namespace} 属于 用户")                            
                            target_user = target_gitlab.users.list(username=source_user_or_group)[0]
                            logging.info(f"项目的所属用户：{target_user.username}")                           
                            logging.info(f"为用户 {target_user.username} 创建项目，仅限管理员才有权操作")
                            target_project = target_user.projects.create({'name': source_project.name})
                            time.sleep(5)
                            logging.info(f"克隆并推送项目> {source_project.name} : {source_project.path_with_namespace}")
                            clone_and_push_project(source_project, target_project)
                        except gitlab.exceptions.GitlabCreateError as e:
                            logging.error(f"在目标 GitLab 中创建项目> {source_project.name} : {source_project.path_with_namespace} 时出错: {e}")
                            with open(projects_error_log_file_path, 'a') as file:
                                file.write(f"sync_target_projects_by_source_projects: 创建项目> {source_project.name} : {source_project.path_with_namespace}  source_project_id: {source_project.id} 时出错.\n")     
                    else:
                        try:
                            logging.info(f"项目> {source_project.name} : {source_project.path_with_namespace} 属于 群组")                            
                            target_groups = target_gitlab.groups.list(search=source_user_or_group, get_all=True)
                            target_group_id = None
                            for target_group in target_groups:
                                if target_group.full_path == source_user_or_group:
                                    found = True
                                    target_group_id = target_group.id
                                    break
                            if  found:                                                                                          
                                logging.info(f"配置项目信息") 
                                project_data = {
                                    'name': source_project.name, 
                                    'path': source_project.path, 
                                    'description': source_project.description, 
                                    'visibility': source_project.visibility,                                 
                                    'namespace_id': target_group_id
                                }       
                                logging.info(f"在 {source_user_or_group} : {target_group.id} 群组中创建项目> {source_project.name} : {source_project.path_with_namespace}")                        
                                target_project = target_gitlab.projects.create(project_data)
                                time.sleep(5)
                                logging.info(f"sync_target_projects_by_source_projects: 克隆并推送项目> {source_project.name} : {source_project.path_with_namespace}")
                                clone_and_push_project(source_project, target_project)
                        except gitlab.exceptions.GitlabCreateError as e:
                            logging.error(f"在目标 GitLab 中创建项目> {source_project.name} : {source_project.path_with_namespace} 时出错: {e}")
                            with open(projects_error_log_file_path, 'a') as file:
                                file.write(f"sync_target_projects_by_source_projects: 创建项目> {source_project.name} : {source_project.path_with_namespace}  source_project_id: {source_project.id} 时出错.\n")                         
    except gitlab.exceptions.GitlabGetError as e:
        logging.error(f"获取项目列表失败: {e}")
    print(f"                                                                                             ")    
    print(f" 。。。。。。…………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的项目同步到目标gitlab上 结束 …………………………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")
    print(f"                                                                                             ")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")






# 将源gitlab上的项目代码同步到目标gitlab上
def clone_and_push_project(source_project, target_project):
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的项目代码同步到目标gitlab上 开始 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ")
    logging.info(f"指定克隆项目的存储路径")
    local_path = os.path.join(clone_project_deposit_path, source_project.path_with_namespace)
    logging.info(f"创建克隆项目的存储路径 {local_path}")
    os.makedirs(local_path, exist_ok=True)
    try:        
        source_project.http_url_to_repo = source_project.http_url_to_repo.replace("://", f"://root:{source_token}@", 1)
        logging.info(f"拼接克隆项目代码仓库 url 链接地址： {source_project.http_url_to_repo}")  
        clone_command = ['git', 'clone', '--mirror', source_project.http_url_to_repo, local_path]
        logging.info(f"拼接克隆项目代码仓库命令： {clone_command}")  
        logging.info(f"开始克隆项目> {source_project.name} : {source_project.path_with_namespace} 代码仓库到本地（使用镜像克隆以获取所有分支和标签）")  
        subprocess.run(clone_command, check=True)
        logging.info(f"进入项目目录并推送到目标GitLab")
        with os.scandir(local_path) as it:
            for entry in it:
                if entry.is_dir():
                    project_dir = entry.path
                    break
        os.chdir(project_dir)
        # 因为我获取到的对象 url 是 http://gitlab.lichengjun.top,而我外部访问的方式是 https://gitlab.lichengjun.top:63922，所以需要替换，如果不是k8s部署的，可以不用替换url,可以将这段.replace(target_k8s_url, target_url)去掉
        #target_project.http_url_to_repo = target_project.http_url_to_repo.replace(target_k8s_url, target_url).replace("://", f"://root:{target_token}@", 1)        
        target_project.http_url_to_repo = target_project.http_url_to_repo.replace("://", f"://root:{target_token}@", 1)
        logging.info(f"拼接推送项目代码仓库 url 链接地址： {target_project.http_url_to_repo}")
        add_remote_command = ['git', 'remote', 'add', 'destination', target_project.http_url_to_repo]
        push_all_command = ['git', 'push', 'destination', '--all']
        push_tags_command = ['git', 'push', 'destination', '--tags']
        logging.info(f"开始推送项目项目> {source_project.name} : {source_project.path_with_namespace} 到目标gitlab")
        logging.info(f"将远程仓库地址 {target_project.http_url_to_repo} 添加到你的本地Git仓库中，并给它命名为destination")
        subprocess.run(add_remote_command, check=True)
        logging.info(f"将本地仓库 {target_project.http_url_to_repo} 中的所有分支推送到名为destination的远程仓库中")
        subprocess.run(push_all_command, check=True)
        logging.info(f"将本地仓库 {target_project.http_url_to_repo} 中的所有标签推送到名为destination的远程仓库中")
        subprocess.run(push_tags_command, check=True)
        time.sleep(5)
        logging.info(f"成功克隆并推送项目> {source_project.name} : {source_project.path_with_namespace}")
    except subprocess.CalledProcessError as e:
        logging.error(f"克隆或推送项目> {source_project.name} : {source_project.path_with_namespace} 时出错: {e}")
        with open(projects_error_log_file_path, 'a') as file:
            file.write(f"clone_and_push_project: 克隆或推送项目> {source_project.name} : {source_project.path_with_namespace}  source_project_id: {source_project.id} 时出错.\n")
    print(f"                                                                                             ")    
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的项目同步到目标gitlab上 结束  ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")
    print(f"                                                                                             ")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")






# 将源gitlab上的项目的单个成员和权限同步到目标gitlab上
def sync_target_project_single_members_by_source_project_single_members(target_project_id, target_user_id, access_level):
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的项目的单个成员和权限同步到目标gitlab上 开始 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。") 
    print(f"                                                                                             ")
    try:
        logging.info(f"获取要同步的项目成员信息")
        target_project = target_gitlab.projects.get(target_project_id)
        logging.info(f"获取要同步的用户信息")
        target_user = target_gitlab.users.get(target_user_id)
        logging.info(f"获取要同步的项目成员信息")
        target_project.members_all.get(target_user_id)
        logging.info(f"在目标gitlab中，项目 {target_project.path_with_namespace} 已经存在项目成员 {target_user.username} ")       
        try:
            logging.info(f"在目标gitlab中，项目 {target_project.path_with_namespace} 不存在项目成员 {target_user.username} ，将其添加到项目成员中")
            target_project.members.create({'user_id': target_user_id, 'access_level': access_level})
        except gitlab.exceptions.GitlabCreateError as e:
            logging.error(f"在目标 GitLab 项目> {source_project.name} : {source_project.path_with_namespace} 中添加项目成员时出错: {e}")
            with open(projects_members_error_log_file_path, 'a') as file:                
                file.write(f"sync_target_project_members_by_source_project_members: 在目标 GitLab 项目> {target_project.name} : {target_project.path_with_namespace}  target_user_id: {target_user_id}   access_level: {access_level} 中添加项目成员时出错: {e}.\n")            
    except gitlab.exceptions.GitlabGetError as e:
        logging.error(f"获取项目-用户-项目成员信息失败: {e}") 
    print(f"                                                                                             ")                
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的项目的单个成员和权限同步到目标gitlab上 结束 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。") 
    print(f"                                                                                             ") 
    print(f"                                                                                             ")
    print(f"                                                                                             ")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")






# 将源gitlab上的项目的成员和权限同步到目标gitlab上
def sync_target_project_members_by_source_project_members():
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的项目的成员和权限同步到目标gitlab上 开始 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。") 
    print(f"                                                                                             ")
    try:
        i = 0
        logging.info(f"分页获取所有项目，避免一次性加载过多数据，假设最多200页，根据实际情况调整")
        for page in range(1, 200):      
            logging.info(f"获取每页100个项目")
            source_projects = source_gitlab.projects.list(per_page=100, page=page, order_by='id', sort='asc')
            if not source_projects:
                logging.info(f"已经获取完所有项目，退出循环")
                break
            for source_project in source_projects:
                print(f" 。。。。。。................................................................................................................................................................................................ 。。。。。。")            
                i += 1
                print(f"")
                print(f"")
                print(f"当前处理第 {i} 个项目")
                print(f"") 
                print(f"")     


                # 这里的判断用于当意外导致同步中断，我们可以通过这个断点继续后面的操作，不用再重复执行已经同步好的操作
                if i < 0:
                    continue 


                logging.info(f"获取源gitlab上的项目> {source_project.name} : {source_project.path_with_namespace} 的所有项目成员")
                source_project_members = source_project.members_all.list(get_all=True)
                logging.info(f"通过源gitlab上的项目> {source_project.name} : {source_project.path_with_namespace} 获取目标gitlab上项目")
                try:
                    target_project = target_gitlab.projects.get(source_project.path_with_namespace)
                    for source_project_member in source_project_members:
                        print(f" 。。。。。。。…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........…………………………..........………………………….......... 。。。。。。")
                        logging.info(f"通过用户名获取单个用户id")
                        user_id = target_gitlab.users.list(username=source_project_member.username)[0].id
                        try:
                            target_project.members_all.get(user_id)
                            logging.info(f"在目标gitlab中的项目>  {source_project.name} : {source_project.path_with_namespace} 已经存在 {source_project_member.username} 项目成员")
                        except gitlab.exceptions.GitlabGetError:
                            try:
                                logging.info(f"在目标gitlab中的项目>  {source_project.name} : {source_project.path_with_namespace} 不存在 {source_project_member.username} 项目成员，将其添加到项目成员中")
                                target_project.members.create({'user_id': user_id, 'access_level': source_project_member.access_level})
                                time.sleep(5)
                            except gitlab.exceptions.GitlabCreateError as e:
                                logging.error(f"在目标 GitLab 项目> {source_project.name} : {source_project.path_with_namespace}  user_id: {user_id} 中添加项目成员时出错: {e}")
                                file.write(f"sync_target_project_members_by_source_project_members: 在目标 GitLab 项目> {source_project.name} : {source_project.path_with_namespace}  target_project_id: {target_project.id}  target_user_id: {user_id}  access_level: {source_project_member.access_level} 中添加项目成员时出错: {e}.\n")
                except gitlab.exceptions.GitlabGetError as e:
                    logging.error(f"获取项目列表失败 {source_project.name} : {source_project.path_with_namespace}: {e}")
                    with open(projects_members_error_log_file_path, 'a') as file:
                        file.write(f"sync_target_project_members_by_source_project_members: 获取项目列表失败> {source_project.name} : {source_project.path_with_namespace}  source_project_id: {source_project.id} 时出错.\n")               
    except gitlab.exceptions.GitlabGetError as e:
        logging.error(f"获取项目列表失败: {e}")
                  
    print(f"                                                                                             ")                
    print(f" 。。。。。。………………………………………………………………………………………………………………………………………………………………………………………………………… 将源gitlab上的项目的成员和权限同步到目标gitlab上 结束 ………………………………………………………………………………………………………………………………………………………………………………………………………… 。。。。。。") 
    print(f"                                                                                             ") 
    print(f"                                                                                             ")
    print(f"                                                                                             ")
    print(f"                                                                                             ") 
    print(f"                                                                                             ")






# 初始化环境,清理脏数据
init()


# 删除目标gitlab上的所有项目
delete_target_all_projects()
time.sleep(300)


# 删除目标gitlab上的所有群组
delete_target_all_groups()
time.sleep(300)


# 删除目标gitlab上的所有用户
delete_target_all_users()
time.sleep(300)


# 将源gitlab上的用户同步到目标gitlab上
sync_target_users_by_source_users()
time.sleep(300)


# 将源gitlab上的群组同步到目标gitlab上
sync_target_groups_by_source_groups()
time.sleep(300)


# 将源gitlab上的群组的组成员同步到目标gitlab上
sync_target_group_members_by_source_group_members()
time.sleep(300)


# 将源gitlab上的项目同步到目标gitlab上
sync_target_projects_by_source_projects()
time.sleep(300)


# # 将源gitlab上的项目的项目成员同步到目标gitlab上
sync_target_project_members_by_source_project_members()
time.sleep(300)


# 将源gitlab上的群组的单个组成员同步到目标gitlab上
# sync_target_single_user_by_source_single_user(90)


# 将源gitlab上的单个项目同步到目标gitlab上
# sync_target_single_groups_by_single_source_groups(132)


# 将源gitlab上的群组的单个组成员同步到目标gitlab上
# sync_target_group_single_members_by_source_group_single_members(7, 5, 40)


# 将源gitlab上的单个项目同步到目标gitlab上
# sync_target_single_projects_by_source_single_projects(787)


# 将源gitlab上的项目的单个成员和权限同步到目标gitlab上
# sync_target_project_single_members_by_source_project_single_members(4, 2, 50)